package Study2;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * 对于String 类的探究
 */
public class Study22 {
    /*
    去除该字符串中的前端的空格，以及后端的空格，中间的空格不去
    trim();
     */
    public static void main(String[] args) {
        String str = "     Hello      World     ";
        String ret = str.trim();
        System.out.println(ret);
    }




    /*
    字符串的截取substring() [) 是左闭右开的
    注意不可以超过所对应的下标位置
     */
    public static void main20(String[] args) {
        String str = "HelloWorld";

        String ret = str.substring(1); // 从下标位置开始截取到最后一个位置
        System.out.println(ret);
        String tmp = str.substring(5,10); // 从下标为5开始截取到下标为9的位置
        System.out.println(tmp);

    }




    /*
    字符的替换
    使用 replace()
     */
    public static void main19(String[] args) {
        String str = "abababcd";
        String ret = str.replace('a','A');
        System.out.println(ret);
        String tmp = str.replace("ab","SS");
        System.out.println(tmp);
        /*
        将字符串中的第一个为 “xx”的字符串或者第一个字符'x'，替换为 “xx”字符串或 字符‘x’
        replaceFirst
         */
        String ret1 = str.replaceFirst("ab","GG");
        System.out.println(ret1);
    }



    /**
     * 字符的比较
     */

    /*
    在String 类中compareTo()的方法，是一个非常重要的方法，该方法返回一个整型
    该数据会根据大小关系返回三类内容
    1.相等 返回0
    2.小于 返回小于0
    3.大于 返回大于 0
     */
 public static void main17(String[] args) {
     String str = "abc";
     String str1 = "abcdef";
     String str2 = "fecb";
     String str3 = "ABCDEF";
     String str4 = "abc";

     System.out.println(str.compareTo(str4));
     System.out.println(str.compareTo(str1));
     System.out.println(str1.compareTo(str2));
     System.out.println(str1.compareTo(str3));
 }

 public static void main18(String[] args) {
     System.out.println("A".compareTo("a"));
     System.out.println("a".compareTo("a"));
     System.out.println("坚".compareTo("持"));
     System.out.println("梦".compareTo("想"));
 }



    /**
     * equal() 是字符的比较区分大小写的
     * equalsIgnoreCase()是不区别字符的的大小写的
     */
    public static void main16(String[] args) {
        String str1  = "ABCDEF";
        String str = "abcdef";

        System.out.println(str.equals(str1)); // 比较结果是区分大小写的
        System.out.println(str.equalsIgnoreCase(str1)); // 比较结果是不区分大小写的
    }

    /**
     * 字符。字节与字符串之间的联系的探究
     */
// 改变编码，编码处理
    public static void main15(String[] args) throws UnsupportedEncodingException {
        String str  = "abcdef";
        byte[] bytes = str.getBytes("utf-8");
        System.out.println(Arrays.toString(bytes));
        String str1 = "高博";
        byte[] bytes1 = str1.getBytes("gbk");
        System.out.println(Arrays.toString(bytes1));
    }
    /*
    那么何时使用 byte[],何时使用char[]呢
    byte[]是把String按照一个字节一个字节的方式处理，这种适合在网络传输，数据存储这样的场景下使用
    更合适，针对二进制数据来操作二进制数据(编译器可以看懂的，class字节码文件)
    char[]是吧 String 按照一个字符一个字符的方式处理，更适合针对文本数据操作
    尤其是包含中文的时候
     */


//    将字符串以字节数组的形式返回getBytes(),返回值是byte类型
    public static void main14(String[] args) {
        String str2 = "abcdef";
        byte[] bytes1 = str2.getBytes(); // 将字符串
        System.out.println(Arrays.toString(bytes1));
    }


//    判断字符串常量中是否存在数字
    public static boolean func(String str) {
        for (int i = 0; i < str.length(); i++) {
            char tmp = str.charAt(i);   // 获取字符串常量中的下标中的单个字符
            if(tmp >= '0' && tmp <= '9') {
                return false;
            }
        }

        return true;
    }
    public static void main13(String[] args) {
        String str = "123hello";
        String str2 = "hello";
        System.out.println(func(str));
        System.out.println(func(str2));

    }


//    将字符串变为数组返回 tocharArray()
    public static void main12(String[] args) {
        String str = "hello";
        char[] val = str.toCharArray();
        System.out.println(Arrays.toString(val));
    }



    // 获取指定位置的字符 charAt() 在括号中输入对应的字符所在的下标位置开始，注意不可以超过所对应的下标
    public static void main11(String[] args) {
        String str = "hello";
        System.out.println(str.charAt(0));
        System.out.println(str.charAt(2));
//        System.out.println(str.charAt(9));  超过下标所对应的位置，所以报出异常条件

    }






    /**
     * intern()手动入池
     */

    public static void main8(String[] args) {
        String str = "hello";
        String str1 = new String("hello").intern(); // 手动入池
        /*
       intern() 手动入池，从现象上来看的
       当前的这个字符串常量池当中是否存在，如果存在，把常量池当中的引用赋值给当前的引用类型变量
                */
        System.out.println(str == str1);

        /*
        在JVM中底层实际上会自动维护个对象池（字符串常量池）
        1.如果现在采用了直接赋值的模式进行String类的对象，实例化操作，那么该实例化对象(字符串内容)将
        自动保存到这个对象池之中
        2.如果下次继续使用直接赋值的模式声明 String类对象，此时对象池之中如若有指定内容，将直接引用
        如若没有，则开辟新的字符串对象，而后将其保存在对象池之中，以供下次使用
         */
        /*
        面试题：请解释，String类中两种对象实例化的区别
        1.直接赋值，只会开辟一块堆内的内存空间，并且该字符串对象可以自动
        保存在对象池中以供下次使用
        2.构造方法，会开辟两块堆内存空间，不会自动保存对象池中，可以使用 intern() 方法手动入池
         */
    }


    /**
     * String的比较
     */
    /*
    注意在使用 equals 字符内容的判断上使用把为空的值放到括号中，防止运行时发生不必要的异常报错
     */
    public static void main7(String[] args) {
        String str = "hello";
        String str1 = null;
        System.out.println(str.equals(null));
//        System.out.println(str1.equals(str));
    }



    public static void main6(String[] args) {
        String str = "hello";
        String str2 = new String("hello");
        System.out.println(str == str2); //false 比较的引用的对象
        System.out.println(str.equals(str2)); // true 比较的是字符串的内容
    }



    /**
     * String 字符串常量是无法修改的
     * @param
     */
    public static void func(String str,char[] val) {
        str = "abcdef";
        val[0] = 's';
    }
    public static void main5(String[] args) {

        String str = "hello";
        char[] val = new char[]{'W'};

        System.out.println(str);
        System.out.println(Arrays.toString(val));
        func(str,val);

        System.out.println(str);  // 传引用，并没有修改到 str 字符串常量
        System.out.println(Arrays.toString(val));
    }


    public static void main4(String[] args) {
        String str = "hello";
        String str2 = str;

        System.out.println(str);
        System.out.println(str2);

        str2 = "abcd"; // 并不算修改字符串，而是让 str1,原来引用指向 “hello”的改为了，指向“abc"的新的对象
        // 如果通过 str1去修改其指向的内容是不成功的，不要以为传引用，就会修改值的内容
        System.out.println(str);
        System.out.println(str2);

    }

    public static void main9(String[] args) {
        String str = "hello"; // 字符常量池 hello
        str = str + "world";  // 字符常量池 hello + world ,helloworld
        str += "!!!";         // !!! helloworld!!!

        System.out.println(str);

        for (int i = 0; i < 6; i++) {
            str += "!";
            // 不要这样写，大大浪费空间，太多不必要的字符常量池的不断的更新

        }
        System.out.println(str);
    }

    // 利用反射是可以，改变字符串常量的
    public static void main10(String[] args) throws NoSuchFieldException, IllegalAccessException {
        String str = "hello";
        Field field = String.class.getDeclaredField("value");
        field.setAccessible(true);
        char[] val = (char[])field.get(str);
        val[0] = 'H';
        System.out.println(str);

    }



    // String 的 ==
    /*
    String 引用类型的 == 比较并不是在比较 字符串的内容，而是比较两个引用是否指向同一个对象
    常量池 —— 字符常量池
    hello 这样的字符串 字面值常量，也是需要一定的内存空间来存储的，
    这样的常量具有一个特点，就是不需要修改（常量），所以如果有代码中有
    多个地方引用都需要使用 “hello” 的话，就直接引用指向到常量池的这个位置就行了
    而没有必要把 “hello"在内存中存储两次
    * */
    public static void main3(String[] args) {
        String str = "hello";
        String str2 = "hel"+"lo";  // 在编译的时候就拼接好了
        String str3 = new String("hel")+"lo";
        System.out.println(str == str2);  // true
        System.out.println(str == str3); // false

    }


    public static void main2(String[] args) {
        String str = "hello";
        String str2 = "hello";
        String str3 = new String("hello");

        System.out.println(str == str2); // true
        System.out.println(str == str3); // false
    }



    // 常见的构造 String 的方式
    public static void main1(String[] args) {
        // 方式一
        String str = "hello";
        System.out.println(str);

        // 方式二:
        String str1 = new String("hello");
        System.out.println(str1);

        // 方式三
        char[] val = new char[]{'h','e','l','l','o'};
        String str3 = new String(val);
        System.out.println(str3);


    }
}
